﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Drawing;
using System.Windows.Forms;

/* Copyright (c) 2014
 * author: Ricky Kratochwil
 * @ date: 2014-05-16
 * @ summary: This class forms the upper abstraction layer for all world calls
*/

namespace Engine
{
	public class CWorldCore
	{
		private CWorld		m_oWorld;

		public CWorldCore()
		{
			m_oWorld			= null;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// UTILITIES

		//[DEPRECATED]
		//Enable trace logs for debug purposes
		// - Traces only engine events
		//@ KR / 2014.05.16
		public void SetLog(bool bMode)
		{
			CLog.EnableLog(bMode);
			CLog.SetLog("WorldCore");  
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// WORLD OPS

		//Create new empty (ice) world
		// - Empty means only consisting of ice, so this function can be used for world creation
		//@ KR / 2014.05.16
		public void CreateWorld(string strName)
		{
			m_oWorld = new CWorld(strName);

			//Set loaded world to animation core for drawing
			CAnimationCore.UpdateWorld(m_oWorld.GetWorldBitmap());
		}

		//Delete existing world
		// - Call this function when closing the application as well
		//@ KR / 2014.05.19
		public void DeleteWorld()
		{
			if(m_oWorld != null)
			{
				m_oWorld.Destroy();
			}
		}

		//Get CWorld object for Player <-> World actions
		//@ KR / 2014.05.19
		internal void GetWorld(ref CWorld pWorld)
		{
			pWorld = m_oWorld;
		}

		//Gives access to the grid dimensions, this meight be needed for drawing
		// - Parameters will be used as return values
		//@ KR / 2014.05.16
		public void GetWorldDimensions(ref int iWidth, ref int iHeight)
		{
			if(m_oWorld != null)
				m_oWorld.GetWorldDimensions(ref iWidth, ref iHeight);
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// BRICKS AND UTILITIES

		//Set brick in CBrick array to specific type
		// - Set new brick on pos, overwrites existing
		// - Demultiplexes different brick types
		// - Correct brick type, neighboring bricks also
		//@ KR / 2014.05.19
		public void SetBrick(int iBrickType, int iX, int iY)
		{
			if (m_oWorld != null)
			{
				m_oWorld.SetBrick(iBrickType, iX, iY);

				CAnimationCore.UpdateWorld(m_oWorld.GetWorldBitmap());
			}
		}

		//Make brick damaged
		//@ KR / 2014.07.09
		public void DamagedBrick(int iX, int iY)
		{
			if (m_oWorld != null)
			{
				m_oWorld.DamageBrick(iX, iY);

				CAnimationCore.UpdateWorld(m_oWorld.GetWorldBitmap());
			}
		}

		//Set utils to provided position
		//@ KR / 2014.06.27
		public void SetUtil(int iUtilType, int iX, int iY, bool bPerma, int iValue = 0)
		{
			if (m_oWorld != null)
			{
				m_oWorld.SetUtil(iUtilType, iX, iY, bPerma, iValue);
			}
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// COINS

		//Get remaining coins on world left to collect
		//@ KR / 2014.06.29
		public int GetCoins()
		{
			if (m_oWorld != null)
				return m_oWorld.GetRemainingCoins();
			return 0;
		}

		//Remove coin at provided position
		//@ KR / 2014.07.07
		public void RemoveCoin(int iX, int iY)
		{
			if (m_oWorld != null)
				m_oWorld.RemoveCoin(iX, iY);
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// COINS

		//Remove power up at provided position
		//@ KR / 2014.07.09
		public void RemovePowerUp(int iX, int iY)
		{
			if (m_oWorld != null)
				m_oWorld.RemovePowerUp(iX, iY);
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// ANIMATION RELATED

		//Get number of animated objects on world
		//@ KR / 2014.07.08
		public int GetAnimatedCount()
		{
			return m_oWorld.GetAnimatedCount();
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// LOAD AND SAVE

		//Save world to file
		//@ KR / 2014.05.19
		public void SaveWorld()
		{
			string			strFilePath;
			FileStream		oWorldFile		= null;
			StreamWriter	oWorldWriter	= null;

			strFilePath = Directory.GetCurrentDirectory() + "\\Worlds\\" + m_oWorld.GetWorldName() + ".gcw";	//Game of Coins world

			try
			{
				//Create or append file
				oWorldFile		= new FileStream(strFilePath, FileMode.Create, FileAccess.Write);
				oWorldWriter	= new StreamWriter(oWorldFile);

				oWorldWriter.Write(m_oWorld.ToString());
			}
			catch (Exception ex)
			{
				MessageBox.Show("Fehler beim Speichern der Welt!\n\n" + ex.Message);
			}

			if(oWorldWriter != null)
				oWorldWriter.Close();
		}

		//Load world
		// - Validate strWorldName before calling LoadWorld!
		//@ KR / 2014.05.19
		public bool LoadWorld(string strWorldName)
		{
			int				iType;
			string			strFilePath;
			string			strTemp;
			FileStream		oWorldFile		= null;
			StreamReader	oWorldReader	= null;

			strFilePath = Directory.GetCurrentDirectory() + "\\Worlds\\" + strWorldName + ".gcw";	//Game of Coins world

			try
			{
				//Open file
				oWorldFile		= new FileStream(strFilePath, FileMode.Open, FileAccess.Read);
				oWorldReader	= new StreamReader(oWorldFile);

				CreateWorld(strWorldName);
				for(int iY = 0; iY < Const.GRIDS_YAXIS; iY++)
				{
					strTemp = oWorldReader.ReadLine();

					for(int iX = 0; iX < Const.GRIDS_XAXIS; iX++)
					{
						iType = Convert.ToInt32(Char.GetNumericValue(strTemp[iX]));		//Convert.ToString yields wrong result, msdn advices to use this function
						
						if(iType < 5)		//All types blow 5 are bricks
						{
							if(iType == Const.BLOCK_ROCK_DAMAGE)
							{
								m_oWorld.SetBrick(Const.BLOCK_ROCK, iX, iY);
								DamagedBrick(iX, iY);
							}
							else
								m_oWorld.SetBrick(iType, iX, iY);
						}
						else
							m_oWorld.SetUtil(iType, iX, iY, true, 10);
					}				
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show("Fehler beim Laden der Welt!\n\n" + ex.Message);
				
				return false;
			}

			if(oWorldReader != null)
				oWorldReader.Close();

			//Set loaded world to animation core for drawing
			CAnimationCore.UpdateWorld(m_oWorld.GetWorldBitmap());

			return true;
		}
	}
}
